library(psrc.travelsurvey)
library(psrccensus)
library(psrcplot)
library(tidycensus)
library(psrcelmer)
library(psrcctpp)

library(tidyverse)
library(gridExtra)
library(sf)

install_psrc_fonts()

options(scipen=999)
# vars_meta$variable

transit and walking frequency

trip mode share by race

ggplot(hts_mode_by_race_4cat, 
       aes(x= mode_simple, y= share, fill= survey)) +
  geom_col(position = "dodge") +
  facet_wrap(~race_4cat)+
  scale_y_continuous(labels = scales::label_percent()) +
  scale_fill_manual(values = psrc_colors$pognbgy_10)+
  geom_errorbar(aes(ymin=share-share_moe, ymax=share+share_moe),
                          width=0.2, position = position_dodge(0.9))+
  labs(title="Trip Mode Share", caption = "2017/2019 and 2021 PSRC Household Travel Surveys")+
  psrc_style() +
  theme(axis.title.x= element_blank(),
        axis.title.y= element_blank(),
          axis.text.x = element_text(angle=45,vjust=1.1, hjust=1.05))

ggplot(hts_mode_by_race_3cat, 
       aes(x= mode_simple, y= share, fill= survey)) +
  geom_col(position = "dodge") +
  facet_wrap(~race_3cat)+
  scale_y_continuous(labels = scales::label_percent()) +
  scale_fill_manual(values = psrc_colors$pognbgy_10)+
  geom_errorbar(aes(ymin=share-share_moe, ymax=share+share_moe),
                          width=0.2, position = position_dodge(0.9))+
  labs(title="Trip Mode Share", caption = "2017/2019 and 2021 PSRC Household Travel Surveys")+
  psrc_style() +
  theme(axis.title.x= element_blank(),
        axis.title.y= element_blank(),
          axis.text.x = element_text(angle=45,vjust=1.1, hjust=1.05))

trip mode share by race (each mode)

all_modes <- list("Drive","Transit","Walk","Bike")

# commute mode share (no WFH) by race (4 categories)
plot_trip_mode_share_by_race <- function(plot_mode){
  
    ggplot(hts_mode_by_race_4cat %>% filter(mode_simple == plot_mode), 
           aes(x= race_4cat, y= share, fill= survey)) +
      geom_col(position = "dodge") +
      scale_y_continuous(labels = scales::label_percent()) +
      scale_fill_manual(values = psrc_colors$purples_inc[c(2,4)])+
      geom_errorbar(aes(ymin=share-share_moe, ymax=share+share_moe),
                              width=0.2, position = position_dodge(0.9))+
      labs(title=paste("Trip Mode Share (", plot_mode, ") by race", sep=""),
      caption = "2017/2019 and 2021 PSRC Household Travel Surveys")+
      psrc_style() +
      theme(axis.title.x= element_blank(),
            axis.title.y= element_blank(),
            axis.text.x = element_text(angle=15, hjust=0.7))
}
for (mode in all_modes){print(plot_trip_mode_share_by_race(mode))}


# commute mode share (no WFH) by race (3 categories)
plot_trip_mode_share_by_race <- function(plot_mode){
  
    ggplot(hts_mode_by_race_3cat %>% filter(mode_simple == plot_mode), 
           aes(x= race_3cat, y= share, fill= survey)) +
      geom_col(position = "dodge") +
      scale_y_continuous(labels = scales::label_percent()) +
      scale_fill_manual(values = psrc_colors$blues_inc[c(3,5)])+
      geom_errorbar(aes(ymin=share-share_moe, ymax=share+share_moe),
                              width=0.2, position = position_dodge(0.9))+
      labs(title=paste("Trip Mode Share (", plot_mode, ") by race", sep=""),
      caption = "2017/2019 and 2021 PSRC Household Travel Surveys")+
      psrc_style() +
      theme(axis.title.x= element_blank(),
            axis.title.y= element_blank())
}
for (mode in all_modes){print(plot_trip_mode_share_by_race(mode))}

commute mode share by race

ggplot(pums_race_commute_19_4cat %>%
         add_row(pums_race_commute_21_4cat) %>% 
         filter(!mode %in% c("Total",NA,"Other"),
                race_4cat %in% c("Asian or Pacific Islander","White alone")), 
       aes(x= mode, y= share, fill= factor(DATA_YEAR))) +
  geom_col(position = "dodge") +
  facet_wrap(~race_4cat)+
  scale_y_continuous(labels = scales::label_percent()) +
  scale_fill_manual(values = psrc_colors$pognbgy_10)+
  geom_errorbar(aes(ymin=share-share_moe, ymax=share+share_moe),
                          width=0.2, position = position_dodge(0.9))+
  labs(title="Commute Mode Share", caption = "2019 and 2021 Public Use Microsample Census data")+
  psrc_style() +
  theme(axis.title.x= element_blank(),
        axis.title.y= element_blank(),
          axis.text.x = element_text(angle=45,vjust=1.1, hjust=1.05))


ggplot(pums_race_commute_19_no_wfm_4cat %>%
         add_row(pums_race_commute_21_no_wfm_4cat) %>% 
         filter(!mode %in% c("Total","Drive",NA,"Other"),
                race_4cat %in% c("Asian or Pacific Islander","White alone")), 
       aes(x= mode, y= share, fill= factor(DATA_YEAR))) +
  geom_col(position = "dodge") +
  facet_wrap(~race_4cat)+
  scale_y_continuous(labels = scales::label_percent()) +
  scale_fill_manual(values = psrc_colors$pognbgy_10)+
  geom_errorbar(aes(ymin=share-share_moe, ymax=share+share_moe),
                          width=0.2, position = position_dodge(0.9))+
  labs(title="Commute Mode Share", caption = "2019 and 2021 Public Use Microsample Census data")+
  psrc_style() +
  theme(axis.title.x= element_blank(),
        axis.title.y= element_blank(),
          axis.text.x = element_text(angle=45,vjust=1.1, hjust=1.05))

commute mode share by race [each mode]


# share of WFH by race (AAPI and other races)
ggplot(pums_race_commute_19_4cat %>%
         add_row(pums_race_commute_21_4cat) %>% 
         filter(mode %in% c("Worked from home")), 
       aes(x= race_4cat, y= share, fill= factor(DATA_YEAR))) +
  geom_col(position = "dodge") +
  # facet_wrap(~race_aapi)+
  scale_y_continuous(labels = scales::label_percent()) +
  scale_fill_manual(values = psrc_colors$oranges_inc[c(2,4)])+
  geom_errorbar(aes(ymin=share-share_moe, ymax=share+share_moe),
                          width=0.2, position = position_dodge(0.9))+
  labs(title="Share of Telework by race", caption = "2019 and 2021 Public Use Microsample Census data")+
  psrc_style() +
  theme(axis.title.x= element_blank(),
        axis.title.y= element_blank(),
              axis.text.x = element_text(angle=15, hjust=0.7))


# share of WFH by race (AAPI, other POC and white)
ggplot(pums_race_commute_19_3cat  %>%
         add_row(pums_race_commute_21_3cat ) %>% 
         filter(mode %in% c("Worked from home")), 
       aes(x= race_3cat, y= share, fill= factor(DATA_YEAR))) +
  geom_col(position = "dodge") +
  # facet_wrap(~race_aapi)+
  scale_y_continuous(labels = scales::label_percent()) +
  scale_fill_manual(values = psrc_colors$oranges_inc[c(2,4)])+
  geom_errorbar(aes(ymin=share-share_moe, ymax=share+share_moe),
                          width=0.2, position = position_dodge(0.9))+
  labs(title="Share of Telework by race", caption = "2019 and 2021 Public Use Microsample Census data")+
  psrc_style() +
  theme(axis.title.x= element_blank(),
        axis.title.y= element_blank())


all_modes <- list("Drive","Public Transit","Walked","Bicycle")

# commute mode share (no WFH) by race (4 categories)
plot_commute_mode_share_by_race <- function(plot_mode){
  
  return(
    ggplot(pums_race_commute_19_no_wfm_4cat  %>%
           add_row(pums_race_commute_21_no_wfm_4cat ) %>% 
           filter(mode %in% c(plot_mode)), 
           aes(x= race_4cat, y= share, fill= factor(DATA_YEAR))) +
      geom_col(position = "dodge") +
      # facet_wrap(~mode,ncol = 4,scales = "free_y")+
      scale_y_continuous(labels = scales::label_percent()) +
      scale_fill_manual(values = psrc_colors$purples_inc[c(2,4)])+
      geom_errorbar(aes(ymin=share-share_moe, ymax=share+share_moe),
                              width=0.2, position = position_dodge(0.9))+
      labs(title=paste("Commute Mode Share (", plot_mode, ") by race", sep=""), 
           caption = "2019 and 2021 Public Use Microsample Census data")+
      psrc_style() +
      theme(axis.title.x= element_blank(),
            axis.title.y= element_blank(),
              axis.text.x = element_text(angle=15, hjust=0.7))
    )

}
for (mode in all_modes){print(plot_commute_mode_share_by_race(mode))}



# commute mode share (no WFH) by race (3 categories)
plot_commute_mode_share_by_race <- function(plot_mode){
  
  return(
    ggplot(pums_race_commute_19_no_wfm_3cat %>%
           add_row(pums_race_commute_21_no_wfm_3cat) %>% 
           filter(mode %in% c(plot_mode)), 
           aes(x= race_3cat, y= share, fill= factor(DATA_YEAR))) +
      geom_col(position = "dodge") +
      # facet_wrap(~mode,ncol = 4,scales = "free_y")+
      scale_y_continuous(labels = scales::label_percent()) +
      scale_fill_manual(values = psrc_colors$blues_inc[c(3,5)])+
      geom_errorbar(aes(ymin=share-share_moe, ymax=share+share_moe),
                              width=0.2, position = position_dodge(0.9))+
      labs(title=paste("Commute Mode Share (", plot_mode, ") by race", sep=""), 
           caption = "2019 and 2021 Public Use Microsample Census data")+
      psrc_style() +
      theme(axis.title.x= element_blank(),
            axis.title.y= element_blank())
    )

}
for (mode in all_modes){print(plot_commute_mode_share_by_race(mode))}

telework share by race by county

# share of WFH by race (AAPI and other races)
ggplot(pums_race_commute_19_3cat_county %>%
         add_row(pums_race_commute_21_3cat_county) %>% 
         filter(mode %in% c("Worked from home")), 
       aes(x= race_3cat, y= share, fill= factor(DATA_YEAR))) +
  geom_col(position = "dodge") +
  facet_wrap(~COUNTY,ncol = 4)+
  scale_y_continuous(labels = scales::label_percent()) +
  scale_fill_manual(values = psrc_colors$oranges_inc[c(2,4)])+
  geom_errorbar(aes(ymin=share-share_moe, ymax=share+share_moe),
                          width=0.2, position = position_dodge(0.9))+
  labs(title="Share of Telework by race by county", caption = "2019 and 2021 Public Use Microsample Census data")+
  psrc_style() +
  theme(axis.title.x= element_blank(),
        axis.title.y= element_blank(),
          axis.text.x = element_text(angle=15,vjust=1.1, hjust=1.05))


plot_commute_mode_share_by_race_by_county <- function(plot_mode){
  
  return(
    ggplot(pums_race_commute_19_no_wfm_3cat_county %>%
             add_row(pums_race_commute_21_no_wfm_3cat_county) %>% 
             filter(mode %in% c(plot_mode)), 
             aes(x= race_3cat, y= share, fill= factor(DATA_YEAR))) +
      geom_col(position = "dodge") +
      facet_wrap(~COUNTY,ncol = 4)+
      scale_y_continuous(labels = scales::label_percent()) +
      scale_fill_manual(values = psrc_colors$blues_inc[c(3,5)])+
      geom_errorbar(aes(ymin=share-share_moe, ymax=share+share_moe),
                              width=0.2, position = position_dodge(0.9))+
      labs(title=paste("Commute Mode Share (",plot_mode,") by race", sep=""), 
           caption = "2019 and 2021 Public Use Microsample Census data")+
      psrc_style() +
      theme(axis.title.x= element_blank(),
            axis.title.y= element_blank(),
              axis.text.x = element_text(angle=15,vjust=1.1, hjust=1.05))
  )

}

all_modes <- list("Drive","Public Transit")

for (mode in all_modes){print(plot_commute_mode_share_by_race_by_county(mode))}

demographic characteristics


# share of WFH by race (AAPI and other races)
ggplot(pums_race_veh_21 %>%
         filter(vehicle == "No vehicle"), 
       aes(x= race_3cat, y= share, fill= factor(DATA_YEAR))) +
  geom_col(position = "dodge") +
  # facet_wrap(~race_aapi)+
  scale_y_continuous(labels = scales::label_percent()) +
  scale_fill_manual(values = psrc_colors$oranges_inc[c(4)])+
  geom_errorbar(aes(ymin=share-share_moe, ymax=share+share_moe),
                          width=0.2, position = position_dodge(0.9))+
  labs(title="Car-free household by race", caption = "2021 Public Use Microsample Census data")+
  psrc_style() +
  theme(axis.title.x= element_blank(),
        axis.title.y= element_blank())



ggplot(pums_race_veh_21_county %>%
         filter(vehicle == "No vehicle"), 
       aes(x= race_3cat, y= share, fill= factor(DATA_YEAR))) +
  geom_col(position = "dodge") +
  facet_wrap(~COUNTY,ncol = 4)+
  scale_y_continuous(labels = scales::label_percent()) +
  scale_fill_manual(values = psrc_colors$oranges_inc[c(4)])+
  geom_errorbar(aes(ymin=share-share_moe, ymax=share+share_moe),
                          width=0.2, position = position_dodge(0.9))+
  labs(title="Car-free household by race by county", caption = "2021 Public Use Microsample Census data")+
  psrc_style() +
  theme(axis.title.x= element_blank(),
        axis.title.y= element_blank(),
          axis.text.x = element_text(angle=15,vjust=1.1, hjust=1.05))


# share of WFH by race (AAPI and other races)
ggplot(pums_race_migrate_21 %>%
         filter(mode %in% c("Worked from home"),
                share_moe>0,
                share>0.4) %>%
         mutate(migrate = fct_reorder(migrate, desc(share))), 
       aes(x= migrate, y= share, fill= factor(DATA_YEAR))) +
  geom_col(position = "dodge") +
  # facet_wrap(~race_aapi)+
  scale_y_continuous(labels = scales::label_percent()) +
  scale_fill_manual(values = psrc_colors$oranges_inc[c(2,4)])+
  geom_errorbar(aes(ymin=share-share_moe, ymax=share+share_moe),
                          width=0.2, position = position_dodge(0.9))+
  labs(title="Share of Telework by race", caption = "2021 Public Use Microsample Census data")+
  psrc_style() +
  theme(axis.title.x= element_blank(),
        axis.title.y= element_blank(),
          axis.text.x = element_text(angle=15, hjust=0.8))


ggplot(purpose_plot %>% filter(race_aapi %in% c("Asian or Pacific Islander","White only")), 
            aes(x=simple_purpose, y=trips_per_person, fill=survey)) +
  geom_col(position = "dodge")+  
  facet_wrap(~race_aapi)+
  geom_errorbar(aes(ymin=trips_per_person-moe_trips_person, ymax=trips_per_person+moe_trips_person),
                width=0.2, position = position_dodge(0.9))+
  scale_y_continuous(limits = c(0,2))+
  scale_fill_discrete_psrc ("gnbopgy_5")+
  labs(title="Trip Purpose", caption = "2017/2019 and 2021 PSRC Household Travel Surveys")+
  psrc_style()+
  theme(axis.title.x= element_blank(),
        axis.title.y= element_blank(),
          axis.text.x = element_text(angle=45,vjust=1.1, hjust=1.05))

ggplot(purpose_plot %>% filter(!race_aapi %in% c("Asian or Pacific Islander","White only")), 
            aes(x=simple_purpose, y=trips_per_person, fill=survey)) +
  geom_col(position = "dodge")+  
  facet_wrap(~race_aapi)+
  geom_errorbar(aes(ymin=trips_per_person-moe_trips_person, ymax=trips_per_person+moe_trips_person),
                width=0.2, position = position_dodge(0.9))+
  scale_y_continuous(limits = c(0,2))+
  scale_fill_discrete_psrc ("gnbopgy_5")+
  labs(title="Trip Purpose", caption = "2017/2019 and 2021 PSRC Household Travel Surveys")+
  psrc_style()+
  theme(axis.title.x= element_blank(),
        axis.title.y= element_blank(),
          axis.text.x = element_text(angle=45,vjust=1.1, hjust=1.05))
ggplot(acs_race_occupation_5year %>% 
         filter(name=="Region",
                occupation!="Total" ) %>%
         wrap_axis(occupation,20) %>%
         mutate(race = stringr::str_wrap(race, width=15)), 
       aes(x= fct_rev(cat), y= occupation_share, fill= race)) +
  geom_col(position = "dodge") +
  scale_y_continuous(labels = label_percent()) +
  scale_fill_manual(values = psrc_colors$pognbgy_10)+
  geom_errorbar(aes(ymin=occupation_share-occupation_moe, ymax=occupation_share+occupation_moe),
                          width=0.2, position = position_dodge(0.9))+
  coord_flip()+
  psrc_style() +
  labs(title="Share of Workers by Industry", caption = "2021 Public Use Microsample Census data")+
  theme(axis.title.x= element_blank(),
        axis.title.y= element_blank(),
        panel.grid.major.y = element_blank(),
      panel.grid.major.x = element_line(color="#cbcbcb"),
      legend.position = "right")
diff <- race_commute_5year %>%
  ungroup() %>%
  add_row(race_commute_1year %>%
  ungroup()) %>%
  filter(race %in% c("Asian only","Native Hawaiian and other Pacific Islander alone"),
         name == "Region",
         mode!="Total")%>%
  mutate(mode = factor(mode, levels=c("Drove alone",
                                       "Carpooled",
                                       "Public transit",
                                       "Walked",
                                       "Other",
                                       "Work from home")),
         acs_type = factor(acs_type,levels=c("acs5","acs1")))

ggplot(diff, aes(x=mode,y=estimate,fill=acs_type))+
  geom_col(position="dodge")+
  scale_fill_manual(values = psrc_colors$pognbgy_10)+
  geom_errorbar(aes(ymin=estimate-moe, ymax=estimate+moe),
                            width=0.2, position = position_dodge(0.9))+
    facet_wrap(~race, scales = "free_y")+
  psrc_style()+
  theme(axis.title.x= element_blank(),
          axis.title.y= element_blank(),
          axis.text.x = element_text(angle=45,vjust=1.1, hjust=1.05))

Place of Birth by race

test <- get_acs_recs(geography = "county", table.names = 'B06004I', years = 2021, acs.type = 'acs5')
  
plot_acs_birth <- function(.data, acs_type){
  .plot_data <- .data %>% 
   mutate(born = stringr::str_wrap(born, width=11),
          race = stringr::str_wrap(race, width=22),
          born = factor(born, levels = c("Born in WA\nstate",
                                         "Born in\nother state",
                                         "Native:\nborn\noutside the\nUS",
                                         "Foreign\nborn")),
          race = factor(race,levels = c("American Indian and\nAlaska Native alone",
                                        "Asian only",
                                        "Black or African\nAmerican alone",
                                        "Hispanic or Latino",
                                        "Native Hawaiian and\nother Pacific Islander\nalone",
                                        "White alone")),
          born_moe = ifelse(is.na(born_moe),0,born_moe))
  ggplot(.plot_data %>% filter(name=="Region"), 
       aes(x= born, y= born_share, fill= race)) +
    geom_col(position = "dodge") +
    scale_y_continuous(labels = label_percent()) +
    scale_fill_manual(values = psrc_colors$pognbgy_10)+
    geom_errorbar(aes(ymin=born_share-born_moe, ymax=born_share+born_moe),
                            width=0.2, position = position_dodge(0.9))+
    psrc_style() +
    labs(title = paste("Place of birth share by race - ACS 2021 [", acs_type, "year] data"))+
    theme(axis.title.x= element_blank(),
          axis.title.y= element_blank())
}
plot_acs_birth(race_birthplace_5year, "5")
plot_acs_birth(race_birthplace_1year, "1")

#old analysis

plot <- data_commute %>% 
   filter(!commute_mode2 %in% c("NA", "Total", "Other modes")) %>%
   wrap_axis(commute_mode2, w=15) %>%
   mutate(cat = factor(cat, levels = c("Drive alone","HOV modes",
                "Public transit","Walk","Bike or micro-\nmobility")))


ggplot(plot, aes(x= cat, y= share, fill= race_aapi)) +
  geom_col(position = "dodge") +
  scale_y_continuous(labels = label_percent()) +
  scale_fill_manual(values = psrc_colors$pognbgy_10)+
  moe_bars+
  psrc_style() +
  labs(title = "Commute mode share by race")+
  theme(axis.title.x= element_blank())
# TODO: change to facet like diff charts
plot_acs_commute <- function(.data, acs_type){
  .plot_data <- .data %>% 
   filter(!mode %in% c("Total")) %>%
   mutate(race = stringr::str_wrap(race, width=22),
          race = factor(race,levels = c("American Indian and\nAlaska Native alone",
                                        "Asian only",
                                        "Black or African\nAmerican alone",
                                        "Hispanic or Latino",
                                        "Native Hawaiian and\nother Pacific Islander\nalone",
                                        "White alone")),
          mode = factor(mode, levels=c("Drove alone",
                                       "Carpooled",
                                       "Public transit",
                                       "Walked",
                                       "Other",
                                       "Work from home")))

  ggplot(.plot_data %>% filter(name=="Region"), aes(x= mode, y= mode_share, fill= race)) +
    geom_col(position = "dodge") +
    scale_y_continuous(labels = label_percent()) +
    scale_fill_manual(values = psrc_colors$pognbgy_10)+
    geom_errorbar(aes(ymin=mode_share-mode_moe, ymax=mode_share+mode_moe),
                            width=0.2, position = position_dodge(0.9))+
    psrc_style() +
    labs(title = paste("Commute mode share by race - ACS 2021 [", acs_type, "year] data"))+
    theme(axis.title.x= element_blank(),
          axis.title.y= element_blank())
}
plot_acs_commute(race_commute_5year, "5")
plot_acs_commute(race_commute_1year, "1")
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7cn0NCmxpYnJhcnkocHNyYy50cmF2ZWxzdXJ2ZXkpDQpsaWJyYXJ5KHBzcmNjZW5zdXMpDQpsaWJyYXJ5KHBzcmNwbG90KQ0KbGlicmFyeSh0aWR5Y2Vuc3VzKQ0KbGlicmFyeShwc3JjZWxtZXIpDQpsaWJyYXJ5KHBzcmNjdHBwKQ0KDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoZ3JpZEV4dHJhKQ0KbGlicmFyeShzZikNCg0KaW5zdGFsbF9wc3JjX2ZvbnRzKCkNCg0Kb3B0aW9ucyhzY2lwZW49OTk5KQ0KIyB2YXJzX21ldGEkdmFyaWFibGUNCg0KYGBgDQoNCmBgYHtyfQ0KdHJhY3QuYXNpYW4gPC1nZXRfYWNzX3JlY3MoZ2VvZ3JhcGh5PSd0cmFjdCcsdGFibGUubmFtZXM9YygnQjAyMDExJykseWVhcnM9YygyMDIxKSkNCnRyYWN0Lm5hLnBpIDwtZ2V0X2Fjc19yZWNzKGdlb2dyYXBoeT0ndHJhY3QnLHRhYmxlLm5hbWVzPWMoJ0IwMjAxMicpLHllYXJzPWMoMjAyMSkpDQoNCnRyYWN0Lmx5ciA8LSBzdF9yZWFkX2VsbWVyZ2VvKCdUUkFDVDIwMjBfTk9XQVRFUicpDQoNCmNyZWF0ZV90cmFjdF9tYXAodHJhY3QudGJsPXRyYWN0LmFzaWFuLCB0cmFjdC5seXI9dHJhY3QubHlyLA0KbWFwLnRpdGxlLnBvc2l0aW9uPSd0b3BsZWZ0JywgbGVnZW5kLnRpdGxlPSdBc2lhbiBBbG9uZSBvciBpbiBDb21iaW5hdGlvbiBQb3B1bGF0aW9uJywNCmxlZ2VuZC5zdWJ0aXRsZT0nQUNTIDIwMjEgKDUgeXIpJykNCmBgYA0KDQoNCmBgYHtyfQ0KY3JlYXRlX3RyYWN0X21hcCh0cmFjdC50Ymw9dHJhY3QubmEucGksIHRyYWN0Lmx5cj10cmFjdC5seXIsDQptYXAudGl0bGUucG9zaXRpb249J3RvcGxlZnQnLCBsZWdlbmQudGl0bGU9J05hdGl2ZSBIYXdhaWlhbiBhbmQgb3RoZXIgUGFjaWZpYyBJc2xhbmRlciBhbG9uZSBvciBpbiBDb21iaW5hdGlvbiBQb3B1bGF0aW9uJywNCmxlZ2VuZC5zdWJ0aXRsZT0nQUNTIDIwMjEgKDUgeXIpJykNCmBgYA0KDQojIHRyYW5zaXQgYW5kIHdhbGtpbmcgZnJlcXVlbmN5DQpgYGB7cn0NCg0KdHJhbnMgPC0gaGh0c19jb3VudChwZXJfZGF0YV8xN18xOSwgDQogICAgICAgICAgICAgICAgICAgZ3JvdXBfdmFycz1jKCJyYWNlX2FhcGkiLCAidHJhbnNpdF9mcmVxMiIpLA0KICAgICAgICAgICAgICAgICAgIHNwZWNfd2d0ID0gImhoX3dlaWdodF8yMDE3XzIwMTlfYWR1bHQiLA0KICAgICAgICAgICBpbmNsX25hID0gRkFMU0UpICU+JQ0KICBhZGRfcm93KGhodHNfY291bnQocGVyX2RhdGFfMjEsIA0KICAgICAgICAgICAgICAgICAgIGdyb3VwX3ZhcnM9YygicmFjZV9hYXBpIiwgInRyYW5zaXRfZnJlcTIiKSwNCiAgICAgICAgICAgICAgICAgICBzcGVjX3dndCA9ICJwZXJzb25fYWR1bHRfd2VpZ2h0XzIwMjEiLA0KICAgICAgICAgICBpbmNsX25hID0gRkFMU0UpKSAlPiUNCiAgZmlsdGVyKHRyYW5zaXRfZnJlcTI9PSJhdCBsZWFzdCAxIGRheS93ZWVrIiwNCiAgICAgICAgICNyYWNlX2FhcGkgJWluJSBjKCJBc2lhbiBvciBQYWNpZmljIElzbGFuZGVyIiwiV2hpdGUgb25seSIpDQogICAgICAgICApDQoNCnRlbGUgPC0gaGh0c19jb3VudChwZXJfZGF0YV8xN18xOSwNCiAgICAgICAgICAgZ3JvdXBfdmFycz1jKCJyYWNlX2FhcGkiLCAid29ya3BsYWNlX3RyYXZlbCIpLA0KICAgICAgICAgICBzcGVjX3dndCA9ICJoaF93ZWlnaHRfMjAxN18yMDE5X2FkdWx0IiwNCiAgICAgICAgICAgaW5jbF9uYSA9IEZBTFNFKSAlPiUNCiAgYWRkX3JvdygNCiAgICBoaHRzX2NvdW50KHBlcl9kYXRhXzIxLA0KICAgICAgICAgICAgICAgZ3JvdXBfdmFycz1jKCJyYWNlX2FhcGkiLCAid29ya3BsYWNlX3RyYXZlbCIpLA0KICAgICAgICAgICAgICAgc3BlY193Z3QgPSAicGVyc29uX2FkdWx0X3dlaWdodF8yMDIxIiwNCiAgICAgICAgICAgICAgIGluY2xfbmEgPSBGQUxTRSkpICU+JQ0KICBmaWx0ZXIoI3JhY2VfYWFwaSAlaW4lIGMoIkFzaWFuIG9yIFBhY2lmaWMgSXNsYW5kZXIiLCJXaGl0ZSBvbmx5IiksDQogICAgICAgICB3b3JrcGxhY2VfdHJhdmVsPT0iV29ya3MgYXQgaG9tZSIpDQoNCmdncGxvdCh0cmFucywgYWVzKHg9cmFjZV9hYXBpLCB5PXNoYXJlLCBmaWxsPXN1cnZleSkpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSsgIA0KICAjIGZhY2V0X3dyYXAofnJhY2VfYWFwaSkrDQogIG1vZV9iYXJzKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPXBlcmNlbnQpICsNCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZV9wc3JjICgiZ25ib3BneV81IikrDQogIGxhYnModGl0bGU9IlRyYW5zaXQgdXNhZ2UgYXQgbGVhc3QgMSBkYXkvd2VlayBieSByYWNlIiwgY2FwdGlvbiA9ICIyMDE3LzIwMTkgYW5kIDIwMjEgUFNSQyBIb3VzZWhvbGQgVHJhdmVsIFN1cnZleXMiKSsNCiAgcHNyY19zdHlsZSgpICsgDQogIHRoZW1lKGF4aXMudGl0bGUueD0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGF4aXMudGl0bGUueT0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTE1LHZqdXN0PTAuOSxoanVzdD0wLjYpKQ0KDQoNCmdncGxvdCh0ZWxlLCBhZXMoeD1yYWNlX2FhcGksIHk9c2hhcmUsIGZpbGw9c3VydmV5KSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpKw0KICAjIGZhY2V0X3dyYXAofnJhY2VfYWFwaSkrDQogIG1vZV9iYXJzKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPXBlcmNlbnQpICsNCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZV9wc3JjICgiZ25ib3BneV81IikrDQogIGxhYnModGl0bGU9IlRlbGV3b3JrIGJ5IHJhY2UiLCBjYXB0aW9uID0gIjIwMTcvMjAxOSBhbmQgMjAyMSBQU1JDIEhvdXNlaG9sZCBUcmF2ZWwgU3VydmV5cyIpKw0KICBwc3JjX3N0eWxlKCkgKw0KICB0aGVtZShheGlzLnRpdGxlLng9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLnRpdGxlLnk9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT0xNSx2anVzdD0wLjksaGp1c3Q9MC42KSkNCg0KDQoNCmBgYA0KDQoNCg0KIyB0cmlwIG1vZGUgc2hhcmUgYnkgcmFjZQ0KYGBge3J9DQpnZ3Bsb3QoaHRzX21vZGVfYnlfcmFjZV80Y2F0LCANCiAgICAgICBhZXMoeD0gbW9kZV9zaW1wbGUsIHk9IHNoYXJlLCBmaWxsPSBzdXJ2ZXkpKSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKw0KICBmYWNldF93cmFwKH5yYWNlXzRjYXQpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpsYWJlbF9wZXJjZW50KCkpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcHNyY19jb2xvcnMkcG9nbmJneV8xMCkrDQogIGdlb21fZXJyb3JiYXIoYWVzKHltaW49c2hhcmUtc2hhcmVfbW9lLCB5bWF4PXNoYXJlK3NoYXJlX21vZSksDQogICAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoPTAuMiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjkpKSsNCiAgbGFicyh0aXRsZT0iVHJpcCBNb2RlIFNoYXJlIiwgY2FwdGlvbiA9ICIyMDE3LzIwMTkgYW5kIDIwMjEgUFNSQyBIb3VzZWhvbGQgVHJhdmVsIFN1cnZleXMiKSsNCiAgcHNyY19zdHlsZSgpICsNCiAgdGhlbWUoYXhpcy50aXRsZS54PSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGl0bGUueT0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LHZqdXN0PTEuMSwgaGp1c3Q9MS4wNSkpDQpnZ3Bsb3QoaHRzX21vZGVfYnlfcmFjZV8zY2F0LCANCiAgICAgICBhZXMoeD0gbW9kZV9zaW1wbGUsIHk9IHNoYXJlLCBmaWxsPSBzdXJ2ZXkpKSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKw0KICBmYWNldF93cmFwKH5yYWNlXzNjYXQpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpsYWJlbF9wZXJjZW50KCkpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcHNyY19jb2xvcnMkcG9nbmJneV8xMCkrDQogIGdlb21fZXJyb3JiYXIoYWVzKHltaW49c2hhcmUtc2hhcmVfbW9lLCB5bWF4PXNoYXJlK3NoYXJlX21vZSksDQogICAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoPTAuMiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjkpKSsNCiAgbGFicyh0aXRsZT0iVHJpcCBNb2RlIFNoYXJlIiwgY2FwdGlvbiA9ICIyMDE3LzIwMTkgYW5kIDIwMjEgUFNSQyBIb3VzZWhvbGQgVHJhdmVsIFN1cnZleXMiKSsNCiAgcHNyY19zdHlsZSgpICsNCiAgdGhlbWUoYXhpcy50aXRsZS54PSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGl0bGUueT0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LHZqdXN0PTEuMSwgaGp1c3Q9MS4wNSkpDQoNCmBgYA0KDQojIHRyaXAgbW9kZSBzaGFyZSBieSByYWNlIChlYWNoIG1vZGUpDQpgYGB7cn0NCmFsbF9tb2RlcyA8LSBsaXN0KCJEcml2ZSIsIlRyYW5zaXQiLCJXYWxrIiwiQmlrZSIpDQoNCiMgY29tbXV0ZSBtb2RlIHNoYXJlIChubyBXRkgpIGJ5IHJhY2UgKDQgY2F0ZWdvcmllcykNCnBsb3RfdHJpcF9tb2RlX3NoYXJlX2J5X3JhY2UgPC0gZnVuY3Rpb24ocGxvdF9tb2RlKXsNCiAgDQogICAgZ2dwbG90KGh0c19tb2RlX2J5X3JhY2VfNGNhdCAlPiUgZmlsdGVyKG1vZGVfc2ltcGxlID09IHBsb3RfbW9kZSksIA0KICAgICAgICAgICBhZXMoeD0gcmFjZV80Y2F0LCB5PSBzaGFyZSwgZmlsbD0gc3VydmV5KSkgKw0KICAgICAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSArDQogICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpsYWJlbF9wZXJjZW50KCkpICsNCiAgICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHBzcmNfY29sb3JzJHB1cnBsZXNfaW5jW2MoMiw0KV0pKw0KICAgICAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1zaGFyZS1zaGFyZV9tb2UsIHltYXg9c2hhcmUrc2hhcmVfbW9lKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoPTAuMiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjkpKSsNCiAgICAgIGxhYnModGl0bGU9cGFzdGUoIlRyaXAgTW9kZSBTaGFyZSAoIiwgcGxvdF9tb2RlLCAiKSBieSByYWNlIiwgc2VwPSIiKSwNCiAgICAgIGNhcHRpb24gPSAiMjAxNy8yMDE5IGFuZCAyMDIxIFBTUkMgSG91c2Vob2xkIFRyYXZlbCBTdXJ2ZXlzIikrDQogICAgICBwc3JjX3N0eWxlKCkgKw0KICAgICAgdGhlbWUoYXhpcy50aXRsZS54PSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICBheGlzLnRpdGxlLnk9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTE1LCBoanVzdD0wLjcpKQ0KfQ0KZm9yIChtb2RlIGluIGFsbF9tb2Rlcyl7cHJpbnQocGxvdF90cmlwX21vZGVfc2hhcmVfYnlfcmFjZShtb2RlKSl9DQoNCiMgY29tbXV0ZSBtb2RlIHNoYXJlIChubyBXRkgpIGJ5IHJhY2UgKDMgY2F0ZWdvcmllcykNCnBsb3RfdHJpcF9tb2RlX3NoYXJlX2J5X3JhY2UgPC0gZnVuY3Rpb24ocGxvdF9tb2RlKXsNCiAgDQogICAgZ2dwbG90KGh0c19tb2RlX2J5X3JhY2VfM2NhdCAlPiUgZmlsdGVyKG1vZGVfc2ltcGxlID09IHBsb3RfbW9kZSksIA0KICAgICAgICAgICBhZXMoeD0gcmFjZV8zY2F0LCB5PSBzaGFyZSwgZmlsbD0gc3VydmV5KSkgKw0KICAgICAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSArDQogICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpsYWJlbF9wZXJjZW50KCkpICsNCiAgICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHBzcmNfY29sb3JzJGJsdWVzX2luY1tjKDMsNSldKSsNCiAgICAgIGdlb21fZXJyb3JiYXIoYWVzKHltaW49c2hhcmUtc2hhcmVfbW9lLCB5bWF4PXNoYXJlK3NoYXJlX21vZSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aWR0aD0wLjIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC45KSkrDQogICAgICBsYWJzKHRpdGxlPXBhc3RlKCJUcmlwIE1vZGUgU2hhcmUgKCIsIHBsb3RfbW9kZSwgIikgYnkgcmFjZSIsIHNlcD0iIiksDQogICAgICBjYXB0aW9uID0gIjIwMTcvMjAxOSBhbmQgMjAyMSBQU1JDIEhvdXNlaG9sZCBUcmF2ZWwgU3VydmV5cyIpKw0KICAgICAgcHNyY19zdHlsZSgpICsNCiAgICAgIHRoZW1lKGF4aXMudGl0bGUueD0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgYXhpcy50aXRsZS55PSBlbGVtZW50X2JsYW5rKCkpDQp9DQpmb3IgKG1vZGUgaW4gYWxsX21vZGVzKXtwcmludChwbG90X3RyaXBfbW9kZV9zaGFyZV9ieV9yYWNlKG1vZGUpKX0NCmBgYA0KDQoNCiMgY29tbXV0ZSBtb2RlIHNoYXJlIGJ5IHJhY2UNCmBgYHtyfQ0KZ2dwbG90KHB1bXNfcmFjZV9jb21tdXRlXzE5XzRjYXQgJT4lDQogICAgICAgICBhZGRfcm93KHB1bXNfcmFjZV9jb21tdXRlXzIxXzRjYXQpICU+JSANCiAgICAgICAgIGZpbHRlcighbW9kZSAlaW4lIGMoIlRvdGFsIixOQSwiT3RoZXIiKSwNCiAgICAgICAgICAgICAgICByYWNlXzRjYXQgJWluJSBjKCJBc2lhbiBvciBQYWNpZmljIElzbGFuZGVyIiwiV2hpdGUgYWxvbmUiKSksIA0KICAgICAgIGFlcyh4PSBtb2RlLCB5PSBzaGFyZSwgZmlsbD0gZmFjdG9yKERBVEFfWUVBUikpKSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKw0KICBmYWNldF93cmFwKH5yYWNlXzRjYXQpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpsYWJlbF9wZXJjZW50KCkpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcHNyY19jb2xvcnMkcG9nbmJneV8xMCkrDQogIGdlb21fZXJyb3JiYXIoYWVzKHltaW49c2hhcmUtc2hhcmVfbW9lLCB5bWF4PXNoYXJlK3NoYXJlX21vZSksDQogICAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoPTAuMiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjkpKSsNCiAgbGFicyh0aXRsZT0iQ29tbXV0ZSBNb2RlIFNoYXJlIiwgY2FwdGlvbiA9ICIyMDE5IGFuZCAyMDIxIFB1YmxpYyBVc2UgTWljcm9zYW1wbGUgQ2Vuc3VzIGRhdGEiKSsNCiAgcHNyY19zdHlsZSgpICsNCiAgdGhlbWUoYXhpcy50aXRsZS54PSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGl0bGUueT0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LHZqdXN0PTEuMSwgaGp1c3Q9MS4wNSkpDQoNCmdncGxvdChwdW1zX3JhY2VfY29tbXV0ZV8xOV9ub193Zm1fNGNhdCAlPiUNCiAgICAgICAgIGFkZF9yb3cocHVtc19yYWNlX2NvbW11dGVfMjFfbm9fd2ZtXzRjYXQpICU+JSANCiAgICAgICAgIGZpbHRlcighbW9kZSAlaW4lIGMoIlRvdGFsIiwiRHJpdmUiLE5BLCJPdGhlciIpLA0KICAgICAgICAgICAgICAgIHJhY2VfNGNhdCAlaW4lIGMoIkFzaWFuIG9yIFBhY2lmaWMgSXNsYW5kZXIiLCJXaGl0ZSBhbG9uZSIpKSwgDQogICAgICAgYWVzKHg9IG1vZGUsIHk9IHNoYXJlLCBmaWxsPSBmYWN0b3IoREFUQV9ZRUFSKSkpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSArDQogIGZhY2V0X3dyYXAofnJhY2VfNGNhdCkrDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX3BlcmNlbnQoKSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBwc3JjX2NvbG9ycyRwb2duYmd5XzEwKSsNCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1zaGFyZS1zaGFyZV9tb2UsIHltYXg9c2hhcmUrc2hhcmVfbW9lKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGg9MC4yLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuOSkpKw0KICBsYWJzKHRpdGxlPSJDb21tdXRlIE1vZGUgU2hhcmUiLCBjYXB0aW9uID0gIjIwMTkgYW5kIDIwMjEgUHVibGljIFVzZSBNaWNyb3NhbXBsZSBDZW5zdXMgZGF0YSIpKw0KICBwc3JjX3N0eWxlKCkgKw0KICB0aGVtZShheGlzLnRpdGxlLng9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aXRsZS55PSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NDUsdmp1c3Q9MS4xLCBoanVzdD0xLjA1KSkNCmBgYA0KDQojIGNvbW11dGUgbW9kZSBzaGFyZSBieSByYWNlIFtlYWNoIG1vZGVdDQpgYGB7cn0NCg0KIyBzaGFyZSBvZiBXRkggYnkgcmFjZSAoQUFQSSBhbmQgb3RoZXIgcmFjZXMpDQpnZ3Bsb3QocHVtc19yYWNlX2NvbW11dGVfMTlfNGNhdCAlPiUNCiAgICAgICAgIGFkZF9yb3cocHVtc19yYWNlX2NvbW11dGVfMjFfNGNhdCkgJT4lIA0KICAgICAgICAgZmlsdGVyKG1vZGUgJWluJSBjKCJXb3JrZWQgZnJvbSBob21lIikpLCANCiAgICAgICBhZXMoeD0gcmFjZV80Y2F0LCB5PSBzaGFyZSwgZmlsbD0gZmFjdG9yKERBVEFfWUVBUikpKSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKw0KICAjIGZhY2V0X3dyYXAofnJhY2VfYWFwaSkrDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX3BlcmNlbnQoKSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBwc3JjX2NvbG9ycyRvcmFuZ2VzX2luY1tjKDIsNCldKSsNCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1zaGFyZS1zaGFyZV9tb2UsIHltYXg9c2hhcmUrc2hhcmVfbW9lKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGg9MC4yLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuOSkpKw0KICBsYWJzKHRpdGxlPSJTaGFyZSBvZiBUZWxld29yayBieSByYWNlIiwgY2FwdGlvbiA9ICIyMDE5IGFuZCAyMDIxIFB1YmxpYyBVc2UgTWljcm9zYW1wbGUgQ2Vuc3VzIGRhdGEiKSsNCiAgcHNyY19zdHlsZSgpICsNCiAgdGhlbWUoYXhpcy50aXRsZS54PSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGl0bGUueT0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT0xNSwgaGp1c3Q9MC43KSkNCg0KIyBzaGFyZSBvZiBXRkggYnkgcmFjZSAoQUFQSSwgb3RoZXIgUE9DIGFuZCB3aGl0ZSkNCmdncGxvdChwdW1zX3JhY2VfY29tbXV0ZV8xOV8zY2F0ICAlPiUNCiAgICAgICAgIGFkZF9yb3cocHVtc19yYWNlX2NvbW11dGVfMjFfM2NhdCApICU+JSANCiAgICAgICAgIGZpbHRlcihtb2RlICVpbiUgYygiV29ya2VkIGZyb20gaG9tZSIpKSwgDQogICAgICAgYWVzKHg9IHJhY2VfM2NhdCwgeT0gc2hhcmUsIGZpbGw9IGZhY3RvcihEQVRBX1lFQVIpKSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsNCiAgIyBmYWNldF93cmFwKH5yYWNlX2FhcGkpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpsYWJlbF9wZXJjZW50KCkpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcHNyY19jb2xvcnMkb3Jhbmdlc19pbmNbYygyLDQpXSkrDQogIGdlb21fZXJyb3JiYXIoYWVzKHltaW49c2hhcmUtc2hhcmVfbW9lLCB5bWF4PXNoYXJlK3NoYXJlX21vZSksDQogICAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoPTAuMiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjkpKSsNCiAgbGFicyh0aXRsZT0iU2hhcmUgb2YgVGVsZXdvcmsgYnkgcmFjZSIsIGNhcHRpb24gPSAiMjAxOSBhbmQgMjAyMSBQdWJsaWMgVXNlIE1pY3Jvc2FtcGxlIENlbnN1cyBkYXRhIikrDQogIHBzcmNfc3R5bGUoKSArDQogIHRoZW1lKGF4aXMudGl0bGUueD0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpdGxlLnk9IGVsZW1lbnRfYmxhbmsoKSkNCg0KYWxsX21vZGVzIDwtIGxpc3QoIkRyaXZlIiwiUHVibGljIFRyYW5zaXQiLCJXYWxrZWQiLCJCaWN5Y2xlIikNCg0KIyBjb21tdXRlIG1vZGUgc2hhcmUgKG5vIFdGSCkgYnkgcmFjZSAoNCBjYXRlZ29yaWVzKQ0KcGxvdF9jb21tdXRlX21vZGVfc2hhcmVfYnlfcmFjZSA8LSBmdW5jdGlvbihwbG90X21vZGUpew0KICANCiAgcmV0dXJuKA0KICAgIGdncGxvdChwdW1zX3JhY2VfY29tbXV0ZV8xOV9ub193Zm1fNGNhdCAgJT4lDQogICAgICAgICAgIGFkZF9yb3cocHVtc19yYWNlX2NvbW11dGVfMjFfbm9fd2ZtXzRjYXQgKSAlPiUgDQogICAgICAgICAgIGZpbHRlcihtb2RlICVpbiUgYyhwbG90X21vZGUpKSwgDQogICAgICAgICAgIGFlcyh4PSByYWNlXzRjYXQsIHk9IHNoYXJlLCBmaWxsPSBmYWN0b3IoREFUQV9ZRUFSKSkpICsNCiAgICAgIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKw0KICAgICAgIyBmYWNldF93cmFwKH5tb2RlLG5jb2wgPSA0LHNjYWxlcyA9ICJmcmVlX3kiKSsNCiAgICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX3BlcmNlbnQoKSkgKw0KICAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcHNyY19jb2xvcnMkcHVycGxlc19pbmNbYygyLDQpXSkrDQogICAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPXNoYXJlLXNoYXJlX21vZSwgeW1heD1zaGFyZStzaGFyZV9tb2UpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGg9MC4yLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuOSkpKw0KICAgICAgbGFicyh0aXRsZT1wYXN0ZSgiQ29tbXV0ZSBNb2RlIFNoYXJlICgiLCBwbG90X21vZGUsICIpIGJ5IHJhY2UiLCBzZXA9IiIpLCANCiAgICAgICAgICAgY2FwdGlvbiA9ICIyMDE5IGFuZCAyMDIxIFB1YmxpYyBVc2UgTWljcm9zYW1wbGUgQ2Vuc3VzIGRhdGEiKSsNCiAgICAgIHBzcmNfc3R5bGUoKSArDQogICAgICB0aGVtZShheGlzLnRpdGxlLng9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgIGF4aXMudGl0bGUueT0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT0xNSwgaGp1c3Q9MC43KSkNCiAgICApDQoNCn0NCmZvciAobW9kZSBpbiBhbGxfbW9kZXMpe3ByaW50KHBsb3RfY29tbXV0ZV9tb2RlX3NoYXJlX2J5X3JhY2UobW9kZSkpfQ0KDQoNCiMgY29tbXV0ZSBtb2RlIHNoYXJlIChubyBXRkgpIGJ5IHJhY2UgKDMgY2F0ZWdvcmllcykNCnBsb3RfY29tbXV0ZV9tb2RlX3NoYXJlX2J5X3JhY2UgPC0gZnVuY3Rpb24ocGxvdF9tb2RlKXsNCiAgDQogIHJldHVybigNCiAgICBnZ3Bsb3QocHVtc19yYWNlX2NvbW11dGVfMTlfbm9fd2ZtXzNjYXQgJT4lDQogICAgICAgICAgIGFkZF9yb3cocHVtc19yYWNlX2NvbW11dGVfMjFfbm9fd2ZtXzNjYXQpICU+JSANCiAgICAgICAgICAgZmlsdGVyKG1vZGUgJWluJSBjKHBsb3RfbW9kZSkpLCANCiAgICAgICAgICAgYWVzKHg9IHJhY2VfM2NhdCwgeT0gc2hhcmUsIGZpbGw9IGZhY3RvcihEQVRBX1lFQVIpKSkgKw0KICAgICAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSArDQogICAgICAjIGZhY2V0X3dyYXAofm1vZGUsbmNvbCA9IDQsc2NhbGVzID0gImZyZWVfeSIpKw0KICAgICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6bGFiZWxfcGVyY2VudCgpKSArDQogICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBwc3JjX2NvbG9ycyRibHVlc19pbmNbYygzLDUpXSkrDQogICAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPXNoYXJlLXNoYXJlX21vZSwgeW1heD1zaGFyZStzaGFyZV9tb2UpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGg9MC4yLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuOSkpKw0KICAgICAgbGFicyh0aXRsZT1wYXN0ZSgiQ29tbXV0ZSBNb2RlIFNoYXJlICgiLCBwbG90X21vZGUsICIpIGJ5IHJhY2UiLCBzZXA9IiIpLCANCiAgICAgICAgICAgY2FwdGlvbiA9ICIyMDE5IGFuZCAyMDIxIFB1YmxpYyBVc2UgTWljcm9zYW1wbGUgQ2Vuc3VzIGRhdGEiKSsNCiAgICAgIHBzcmNfc3R5bGUoKSArDQogICAgICB0aGVtZShheGlzLnRpdGxlLng9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgIGF4aXMudGl0bGUueT0gZWxlbWVudF9ibGFuaygpKQ0KICAgICkNCg0KfQ0KZm9yIChtb2RlIGluIGFsbF9tb2Rlcyl7cHJpbnQocGxvdF9jb21tdXRlX21vZGVfc2hhcmVfYnlfcmFjZShtb2RlKSl9DQoNCmBgYA0KDQojIHRlbGV3b3JrIHNoYXJlIGJ5IHJhY2UgYnkgY291bnR5DQpgYGB7cn0NCiMgc2hhcmUgb2YgV0ZIIGJ5IHJhY2UgKEFBUEkgYW5kIG90aGVyIHJhY2VzKQ0KZ2dwbG90KHB1bXNfcmFjZV9jb21tdXRlXzE5XzNjYXRfY291bnR5ICU+JQ0KICAgICAgICAgYWRkX3JvdyhwdW1zX3JhY2VfY29tbXV0ZV8yMV8zY2F0X2NvdW50eSkgJT4lIA0KICAgICAgICAgZmlsdGVyKG1vZGUgJWluJSBjKCJXb3JrZWQgZnJvbSBob21lIikpLCANCiAgICAgICBhZXMoeD0gcmFjZV8zY2F0LCB5PSBzaGFyZSwgZmlsbD0gZmFjdG9yKERBVEFfWUVBUikpKSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKw0KICBmYWNldF93cmFwKH5DT1VOVFksbmNvbCA9IDQpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpsYWJlbF9wZXJjZW50KCkpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcHNyY19jb2xvcnMkb3Jhbmdlc19pbmNbYygyLDQpXSkrDQogIGdlb21fZXJyb3JiYXIoYWVzKHltaW49c2hhcmUtc2hhcmVfbW9lLCB5bWF4PXNoYXJlK3NoYXJlX21vZSksDQogICAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoPTAuMiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjkpKSsNCiAgbGFicyh0aXRsZT0iU2hhcmUgb2YgVGVsZXdvcmsgYnkgcmFjZSBieSBjb3VudHkiLCBjYXB0aW9uID0gIjIwMTkgYW5kIDIwMjEgUHVibGljIFVzZSBNaWNyb3NhbXBsZSBDZW5zdXMgZGF0YSIpKw0KICBwc3JjX3N0eWxlKCkgKw0KICB0aGVtZShheGlzLnRpdGxlLng9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aXRsZS55PSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9MTUsdmp1c3Q9MS4xLCBoanVzdD0xLjA1KSkNCg0KcGxvdF9jb21tdXRlX21vZGVfc2hhcmVfYnlfcmFjZV9ieV9jb3VudHkgPC0gZnVuY3Rpb24ocGxvdF9tb2RlKXsNCiAgDQogIHJldHVybigNCiAgICBnZ3Bsb3QocHVtc19yYWNlX2NvbW11dGVfMTlfbm9fd2ZtXzNjYXRfY291bnR5ICU+JQ0KICAgICAgICAgICAgIGFkZF9yb3cocHVtc19yYWNlX2NvbW11dGVfMjFfbm9fd2ZtXzNjYXRfY291bnR5KSAlPiUgDQogICAgICAgICAgICAgZmlsdGVyKG1vZGUgJWluJSBjKHBsb3RfbW9kZSkpLCANCiAgICAgICAgICAgICBhZXMoeD0gcmFjZV8zY2F0LCB5PSBzaGFyZSwgZmlsbD0gZmFjdG9yKERBVEFfWUVBUikpKSArDQogICAgICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsNCiAgICAgIGZhY2V0X3dyYXAofkNPVU5UWSxuY29sID0gNCkrDQogICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpsYWJlbF9wZXJjZW50KCkpICsNCiAgICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHBzcmNfY29sb3JzJGJsdWVzX2luY1tjKDMsNSldKSsNCiAgICAgIGdlb21fZXJyb3JiYXIoYWVzKHltaW49c2hhcmUtc2hhcmVfbW9lLCB5bWF4PXNoYXJlK3NoYXJlX21vZSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aWR0aD0wLjIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC45KSkrDQogICAgICBsYWJzKHRpdGxlPXBhc3RlKCJDb21tdXRlIE1vZGUgU2hhcmUgKCIscGxvdF9tb2RlLCIpIGJ5IHJhY2UiLCBzZXA9IiIpLCANCiAgICAgICAgICAgY2FwdGlvbiA9ICIyMDE5IGFuZCAyMDIxIFB1YmxpYyBVc2UgTWljcm9zYW1wbGUgQ2Vuc3VzIGRhdGEiKSsNCiAgICAgIHBzcmNfc3R5bGUoKSArDQogICAgICB0aGVtZShheGlzLnRpdGxlLng9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgIGF4aXMudGl0bGUueT0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT0xNSx2anVzdD0xLjEsIGhqdXN0PTEuMDUpKQ0KICApDQoNCn0NCg0KYWxsX21vZGVzIDwtIGxpc3QoIkRyaXZlIiwiUHVibGljIFRyYW5zaXQiKQ0KDQpmb3IgKG1vZGUgaW4gYWxsX21vZGVzKXtwcmludChwbG90X2NvbW11dGVfbW9kZV9zaGFyZV9ieV9yYWNlX2J5X2NvdW50eShtb2RlKSl9DQpgYGANCg0KIyBkZW1vZ3JhcGhpYyBjaGFyYWN0ZXJpc3RpY3MNCmBgYHtyfQ0KDQojIHNoYXJlIG9mIFdGSCBieSByYWNlIChBQVBJIGFuZCBvdGhlciByYWNlcykNCmdncGxvdChwdW1zX3JhY2VfdmVoXzIxICU+JQ0KICAgICAgICAgZmlsdGVyKHZlaGljbGUgPT0gIk5vIHZlaGljbGUiKSwgDQogICAgICAgYWVzKHg9IHJhY2VfM2NhdCwgeT0gc2hhcmUsIGZpbGw9IGZhY3RvcihEQVRBX1lFQVIpKSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsNCiAgIyBmYWNldF93cmFwKH5yYWNlX2FhcGkpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpsYWJlbF9wZXJjZW50KCkpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcHNyY19jb2xvcnMkb3Jhbmdlc19pbmNbYyg0KV0pKw0KICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPXNoYXJlLXNoYXJlX21vZSwgeW1heD1zaGFyZStzaGFyZV9tb2UpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB3aWR0aD0wLjIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC45KSkrDQogIGxhYnModGl0bGU9IkNhci1mcmVlIGhvdXNlaG9sZCBieSByYWNlIiwgY2FwdGlvbiA9ICIyMDIxIFB1YmxpYyBVc2UgTWljcm9zYW1wbGUgQ2Vuc3VzIGRhdGEiKSsNCiAgcHNyY19zdHlsZSgpICsNCiAgdGhlbWUoYXhpcy50aXRsZS54PSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGl0bGUueT0gZWxlbWVudF9ibGFuaygpKQ0KDQoNCmdncGxvdChwdW1zX3JhY2VfdmVoXzIxX2NvdW50eSAlPiUNCiAgICAgICAgIGZpbHRlcih2ZWhpY2xlID09ICJObyB2ZWhpY2xlIiksIA0KICAgICAgIGFlcyh4PSByYWNlXzNjYXQsIHk9IHNoYXJlLCBmaWxsPSBmYWN0b3IoREFUQV9ZRUFSKSkpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSArDQogIGZhY2V0X3dyYXAofkNPVU5UWSxuY29sID0gNCkrDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX3BlcmNlbnQoKSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBwc3JjX2NvbG9ycyRvcmFuZ2VzX2luY1tjKDQpXSkrDQogIGdlb21fZXJyb3JiYXIoYWVzKHltaW49c2hhcmUtc2hhcmVfbW9lLCB5bWF4PXNoYXJlK3NoYXJlX21vZSksDQogICAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoPTAuMiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjkpKSsNCiAgbGFicyh0aXRsZT0iQ2FyLWZyZWUgaG91c2Vob2xkIGJ5IHJhY2UgYnkgY291bnR5IiwgY2FwdGlvbiA9ICIyMDIxIFB1YmxpYyBVc2UgTWljcm9zYW1wbGUgQ2Vuc3VzIGRhdGEiKSsNCiAgcHNyY19zdHlsZSgpICsNCiAgdGhlbWUoYXhpcy50aXRsZS54PSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGl0bGUueT0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTE1LHZqdXN0PTEuMSwgaGp1c3Q9MS4wNSkpDQpgYGANCg0KDQpgYGB7cn0NCg0KIyBzaGFyZSBvZiBXRkggYnkgcmFjZSAoQUFQSSBhbmQgb3RoZXIgcmFjZXMpDQpnZ3Bsb3QocHVtc19yYWNlX21pZ3JhdGVfMjEgJT4lDQogICAgICAgICBmaWx0ZXIobW9kZSAlaW4lIGMoIldvcmtlZCBmcm9tIGhvbWUiKSwNCiAgICAgICAgICAgICAgICBzaGFyZV9tb2U+MCwNCiAgICAgICAgICAgICAgICBzaGFyZT4wLjQpICU+JQ0KICAgICAgICAgbXV0YXRlKG1pZ3JhdGUgPSBmY3RfcmVvcmRlcihtaWdyYXRlLCBkZXNjKHNoYXJlKSkpLCANCiAgICAgICBhZXMoeD0gbWlncmF0ZSwgeT0gc2hhcmUsIGZpbGw9IGZhY3RvcihEQVRBX1lFQVIpKSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsNCiAgIyBmYWNldF93cmFwKH5yYWNlX2FhcGkpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpsYWJlbF9wZXJjZW50KCkpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcHNyY19jb2xvcnMkb3Jhbmdlc19pbmNbYygyLDQpXSkrDQogIGdlb21fZXJyb3JiYXIoYWVzKHltaW49c2hhcmUtc2hhcmVfbW9lLCB5bWF4PXNoYXJlK3NoYXJlX21vZSksDQogICAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoPTAuMiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjkpKSsNCiAgbGFicyh0aXRsZT0iU2hhcmUgb2YgVGVsZXdvcmsgYnkgcmFjZSIsIGNhcHRpb24gPSAiMjAyMSBQdWJsaWMgVXNlIE1pY3Jvc2FtcGxlIENlbnN1cyBkYXRhIikrDQogIHBzcmNfc3R5bGUoKSArDQogIHRoZW1lKGF4aXMudGl0bGUueD0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpdGxlLnk9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT0xNSwgaGp1c3Q9MC44KSkNCg0KYGBgDQoNCg0KYGBge3J9DQoNCmdncGxvdChwdXJwb3NlX3Bsb3QgJT4lIGZpbHRlcihyYWNlX2FhcGkgJWluJSBjKCJBc2lhbiBvciBQYWNpZmljIElzbGFuZGVyIiwiV2hpdGUgb25seSIpKSwgDQogICAgICAgICAgICBhZXMoeD1zaW1wbGVfcHVycG9zZSwgeT10cmlwc19wZXJfcGVyc29uLCBmaWxsPXN1cnZleSkpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSsgIA0KICBmYWNldF93cmFwKH5yYWNlX2FhcGkpKw0KICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPXRyaXBzX3Blcl9wZXJzb24tbW9lX3RyaXBzX3BlcnNvbiwgeW1heD10cmlwc19wZXJfcGVyc29uK21vZV90cmlwc19wZXJzb24pLA0KICAgICAgICAgICAgICAgIHdpZHRoPTAuMiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjkpKSsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwyKSkrDQogIHNjYWxlX2ZpbGxfZGlzY3JldGVfcHNyYyAoImduYm9wZ3lfNSIpKw0KICBsYWJzKHRpdGxlPSJUcmlwIFB1cnBvc2UiLCBjYXB0aW9uID0gIjIwMTcvMjAxOSBhbmQgMjAyMSBQU1JDIEhvdXNlaG9sZCBUcmF2ZWwgU3VydmV5cyIpKw0KICBwc3JjX3N0eWxlKCkrDQogIHRoZW1lKGF4aXMudGl0bGUueD0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpdGxlLnk9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT00NSx2anVzdD0xLjEsIGhqdXN0PTEuMDUpKQ0KDQpnZ3Bsb3QocHVycG9zZV9wbG90ICU+JSBmaWx0ZXIoIXJhY2VfYWFwaSAlaW4lIGMoIkFzaWFuIG9yIFBhY2lmaWMgSXNsYW5kZXIiLCJXaGl0ZSBvbmx5IikpLCANCiAgICAgICAgICAgIGFlcyh4PXNpbXBsZV9wdXJwb3NlLCB5PXRyaXBzX3Blcl9wZXJzb24sIGZpbGw9c3VydmV5KSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpKyAgDQogIGZhY2V0X3dyYXAofnJhY2VfYWFwaSkrDQogIGdlb21fZXJyb3JiYXIoYWVzKHltaW49dHJpcHNfcGVyX3BlcnNvbi1tb2VfdHJpcHNfcGVyc29uLCB5bWF4PXRyaXBzX3Blcl9wZXJzb24rbW9lX3RyaXBzX3BlcnNvbiksDQogICAgICAgICAgICAgICAgd2lkdGg9MC4yLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuOSkpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLDIpKSsNCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZV9wc3JjICgiZ25ib3BneV81IikrDQogIGxhYnModGl0bGU9IlRyaXAgUHVycG9zZSIsIGNhcHRpb24gPSAiMjAxNy8yMDE5IGFuZCAyMDIxIFBTUkMgSG91c2Vob2xkIFRyYXZlbCBTdXJ2ZXlzIikrDQogIHBzcmNfc3R5bGUoKSsNCiAgdGhlbWUoYXhpcy50aXRsZS54PSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGl0bGUueT0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LHZqdXN0PTEuMSwgaGp1c3Q9MS4wNSkpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoYWNzX3JhY2Vfb2NjdXBhdGlvbl81eWVhciAlPiUgDQogICAgICAgICBmaWx0ZXIobmFtZT09IlJlZ2lvbiIsDQogICAgICAgICAgICAgICAgb2NjdXBhdGlvbiE9IlRvdGFsIiApICU+JQ0KICAgICAgICAgd3JhcF9heGlzKG9jY3VwYXRpb24sMjApICU+JQ0KICAgICAgICAgbXV0YXRlKHJhY2UgPSBzdHJpbmdyOjpzdHJfd3JhcChyYWNlLCB3aWR0aD0xNSkpLCANCiAgICAgICBhZXMoeD0gZmN0X3JldihjYXQpLCB5PSBvY2N1cGF0aW9uX3NoYXJlLCBmaWxsPSByYWNlKSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGxhYmVsX3BlcmNlbnQoKSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBwc3JjX2NvbG9ycyRwb2duYmd5XzEwKSsNCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1vY2N1cGF0aW9uX3NoYXJlLW9jY3VwYXRpb25fbW9lLCB5bWF4PW9jY3VwYXRpb25fc2hhcmUrb2NjdXBhdGlvbl9tb2UpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB3aWR0aD0wLjIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC45KSkrDQogIGNvb3JkX2ZsaXAoKSsNCiAgcHNyY19zdHlsZSgpICsNCiAgbGFicyh0aXRsZT0iU2hhcmUgb2YgV29ya2VycyBieSBJbmR1c3RyeSIsIGNhcHRpb24gPSAiMjAyMSBQdWJsaWMgVXNlIE1pY3Jvc2FtcGxlIENlbnN1cyBkYXRhIikrDQogIHRoZW1lKGF4aXMudGl0bGUueD0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpdGxlLnk9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9saW5lKGNvbG9yPSIjY2JjYmNiIiksDQogICAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKQ0KDQpgYGANCg0KDQpgYGB7cn0NCg0KYGBgDQoNCg0KYGBge3IgZGlmZmVyZW5jZSBiZXR3ZWVuIDEgYW5kIDUgeWVhciBkYXRhfQ0KZGlmZiA8LSByYWNlX2NvbW11dGVfNXllYXIgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgYWRkX3JvdyhyYWNlX2NvbW11dGVfMXllYXIgJT4lDQogIHVuZ3JvdXAoKSkgJT4lDQogIGZpbHRlcihyYWNlICVpbiUgYygiQXNpYW4gb25seSIsIk5hdGl2ZSBIYXdhaWlhbiBhbmQgb3RoZXIgUGFjaWZpYyBJc2xhbmRlciBhbG9uZSIpLA0KICAgICAgICAgbmFtZSA9PSAiUmVnaW9uIiwNCiAgICAgICAgIG1vZGUhPSJUb3RhbCIpJT4lDQogIG11dGF0ZShtb2RlID0gZmFjdG9yKG1vZGUsIGxldmVscz1jKCJEcm92ZSBhbG9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ2FycG9vbGVkIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQdWJsaWMgdHJhbnNpdCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiV2Fsa2VkIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiV29yayBmcm9tIGhvbWUiKSksDQogICAgICAgICBhY3NfdHlwZSA9IGZhY3RvcihhY3NfdHlwZSxsZXZlbHM9YygiYWNzNSIsImFjczEiKSkpDQoNCmdncGxvdChkaWZmLCBhZXMoeD1tb2RlLHk9ZXN0aW1hdGUsZmlsbD1hY3NfdHlwZSkpKw0KICBnZW9tX2NvbChwb3NpdGlvbj0iZG9kZ2UiKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcHNyY19jb2xvcnMkcG9nbmJneV8xMCkrDQogIGdlb21fZXJyb3JiYXIoYWVzKHltaW49ZXN0aW1hdGUtbW9lLCB5bWF4PWVzdGltYXRlK21vZSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGg9MC4yLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuOSkpKw0KICAgIGZhY2V0X3dyYXAofnJhY2UsIHNjYWxlcyA9ICJmcmVlX3kiKSsNCiAgcHNyY19zdHlsZSgpKw0KICB0aGVtZShheGlzLnRpdGxlLng9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLnRpdGxlLnk9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT00NSx2anVzdD0xLjEsIGhqdXN0PTEuMDUpKQ0KYGBgDQoNCiMgUGxhY2Ugb2YgQmlydGggYnkgcmFjZQ0KYGBge3J9DQp0ZXN0IDwtIGdldF9hY3NfcmVjcyhnZW9ncmFwaHkgPSAiY291bnR5IiwgdGFibGUubmFtZXMgPSAnQjA2MDA0SScsIHllYXJzID0gMjAyMSwgYWNzLnR5cGUgPSAnYWNzNScpDQogIA0KcGxvdF9hY3NfYmlydGggPC0gZnVuY3Rpb24oLmRhdGEsIGFjc190eXBlKXsNCiAgLnBsb3RfZGF0YSA8LSAuZGF0YSAlPiUgDQogICBtdXRhdGUoYm9ybiA9IHN0cmluZ3I6OnN0cl93cmFwKGJvcm4sIHdpZHRoPTExKSwNCiAgICAgICAgICByYWNlID0gc3RyaW5ncjo6c3RyX3dyYXAocmFjZSwgd2lkdGg9MjIpLA0KICAgICAgICAgIGJvcm4gPSBmYWN0b3IoYm9ybiwgbGV2ZWxzID0gYygiQm9ybiBpbiBXQVxuc3RhdGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQm9ybiBpblxub3RoZXIgc3RhdGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTmF0aXZlOlxuYm9yblxub3V0c2lkZSB0aGVcblVTIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZvcmVpZ25cbmJvcm4iKSksDQogICAgICAgICAgcmFjZSA9IGZhY3RvcihyYWNlLGxldmVscyA9IGMoIkFtZXJpY2FuIEluZGlhbiBhbmRcbkFsYXNrYSBOYXRpdmUgYWxvbmUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBc2lhbiBvbmx5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQmxhY2sgb3IgQWZyaWNhblxuQW1lcmljYW4gYWxvbmUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJIaXNwYW5pYyBvciBMYXRpbm8iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOYXRpdmUgSGF3YWlpYW4gYW5kXG5vdGhlciBQYWNpZmljIElzbGFuZGVyXG5hbG9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIldoaXRlIGFsb25lIikpLA0KICAgICAgICAgIGJvcm5fbW9lID0gaWZlbHNlKGlzLm5hKGJvcm5fbW9lKSwwLGJvcm5fbW9lKSkNCiAgZ2dwbG90KC5wbG90X2RhdGEgJT4lIGZpbHRlcihuYW1lPT0iUmVnaW9uIiksIA0KICAgICAgIGFlcyh4PSBib3JuLCB5PSBib3JuX3NoYXJlLCBmaWxsPSByYWNlKSkgKw0KICAgIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKw0KICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9wZXJjZW50KCkpICsNCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBwc3JjX2NvbG9ycyRwb2duYmd5XzEwKSsNCiAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPWJvcm5fc2hhcmUtYm9ybl9tb2UsIHltYXg9Ym9ybl9zaGFyZStib3JuX21vZSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGg9MC4yLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuOSkpKw0KICAgIHBzcmNfc3R5bGUoKSArDQogICAgbGFicyh0aXRsZSA9IHBhc3RlKCJQbGFjZSBvZiBiaXJ0aCBzaGFyZSBieSByYWNlIC0gQUNTIDIwMjEgWyIsIGFjc190eXBlLCAieWVhcl0gZGF0YSIpKSsNCiAgICB0aGVtZShheGlzLnRpdGxlLng9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLnRpdGxlLnk9IGVsZW1lbnRfYmxhbmsoKSkNCn0NCnBsb3RfYWNzX2JpcnRoKHJhY2VfYmlydGhwbGFjZV81eWVhciwgIjUiKQ0KcGxvdF9hY3NfYmlydGgocmFjZV9iaXJ0aHBsYWNlXzF5ZWFyLCAiMSIpDQpgYGANCiNvbGQgYW5hbHlzaXMNCmBgYHtyfQ0KcGxvdCA8LSBkYXRhX2NvbW11dGUgJT4lIA0KICAgZmlsdGVyKCFjb21tdXRlX21vZGUyICVpbiUgYygiTkEiLCAiVG90YWwiLCAiT3RoZXIgbW9kZXMiKSkgJT4lDQogICB3cmFwX2F4aXMoY29tbXV0ZV9tb2RlMiwgdz0xNSkgJT4lDQogICBtdXRhdGUoY2F0ID0gZmFjdG9yKGNhdCwgbGV2ZWxzID0gYygiRHJpdmUgYWxvbmUiLCJIT1YgbW9kZXMiLA0KICAgICAgICAgICAgICAgICJQdWJsaWMgdHJhbnNpdCIsIldhbGsiLCJCaWtlIG9yIG1pY3JvLVxubW9iaWxpdHkiKSkpDQoNCg0KZ2dwbG90KHBsb3QsIGFlcyh4PSBjYXQsIHk9IHNoYXJlLCBmaWxsPSByYWNlX2FhcGkpKSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gbGFiZWxfcGVyY2VudCgpKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHBzcmNfY29sb3JzJHBvZ25iZ3lfMTApKw0KICBtb2VfYmFycysNCiAgcHNyY19zdHlsZSgpICsNCiAgbGFicyh0aXRsZSA9ICJDb21tdXRlIG1vZGUgc2hhcmUgYnkgcmFjZSIpKw0KICB0aGVtZShheGlzLnRpdGxlLng9IGVsZW1lbnRfYmxhbmsoKSkNCmBgYA0KDQpgYGB7ciBBQ1MgY29tbXV0ZSBieSByYWNlfQ0KIyBUT0RPOiBjaGFuZ2UgdG8gZmFjZXQgbGlrZSBkaWZmIGNoYXJ0cw0KcGxvdF9hY3NfY29tbXV0ZSA8LSBmdW5jdGlvbiguZGF0YSwgYWNzX3R5cGUpew0KICAucGxvdF9kYXRhIDwtIC5kYXRhICU+JSANCiAgIGZpbHRlcighbW9kZSAlaW4lIGMoIlRvdGFsIikpICU+JQ0KICAgbXV0YXRlKHJhY2UgPSBzdHJpbmdyOjpzdHJfd3JhcChyYWNlLCB3aWR0aD0yMiksDQogICAgICAgICAgcmFjZSA9IGZhY3RvcihyYWNlLGxldmVscyA9IGMoIkFtZXJpY2FuIEluZGlhbiBhbmRcbkFsYXNrYSBOYXRpdmUgYWxvbmUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBc2lhbiBvbmx5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQmxhY2sgb3IgQWZyaWNhblxuQW1lcmljYW4gYWxvbmUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJIaXNwYW5pYyBvciBMYXRpbm8iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOYXRpdmUgSGF3YWlpYW4gYW5kXG5vdGhlciBQYWNpZmljIElzbGFuZGVyXG5hbG9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIldoaXRlIGFsb25lIikpLA0KICAgICAgICAgIG1vZGUgPSBmYWN0b3IobW9kZSwgbGV2ZWxzPWMoIkRyb3ZlIGFsb25lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDYXJwb29sZWQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlB1YmxpYyB0cmFuc2l0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXYWxrZWQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90aGVyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXb3JrIGZyb20gaG9tZSIpKSkNCg0KICBnZ3Bsb3QoLnBsb3RfZGF0YSAlPiUgZmlsdGVyKG5hbWU9PSJSZWdpb24iKSwgYWVzKHg9IG1vZGUsIHk9IG1vZGVfc2hhcmUsIGZpbGw9IHJhY2UpKSArDQogICAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSArDQogICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGxhYmVsX3BlcmNlbnQoKSkgKw0KICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHBzcmNfY29sb3JzJHBvZ25iZ3lfMTApKw0KICAgIGdlb21fZXJyb3JiYXIoYWVzKHltaW49bW9kZV9zaGFyZS1tb2RlX21vZSwgeW1heD1tb2RlX3NoYXJlK21vZGVfbW9lKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aWR0aD0wLjIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC45KSkrDQogICAgcHNyY19zdHlsZSgpICsNCiAgICBsYWJzKHRpdGxlID0gcGFzdGUoIkNvbW11dGUgbW9kZSBzaGFyZSBieSByYWNlIC0gQUNTIDIwMjEgWyIsIGFjc190eXBlLCAieWVhcl0gZGF0YSIpKSsNCiAgICB0aGVtZShheGlzLnRpdGxlLng9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLnRpdGxlLnk9IGVsZW1lbnRfYmxhbmsoKSkNCn0NCnBsb3RfYWNzX2NvbW11dGUocmFjZV9jb21tdXRlXzV5ZWFyLCAiNSIpDQpwbG90X2Fjc19jb21tdXRlKHJhY2VfY29tbXV0ZV8xeWVhciwgIjEiKQ0KYGBg